package com.ayz.gateway.sdk.gatawayService;

import cn.hutool.core.thread.ThreadFactoryBuilder;
import cn.hutool.log.Log;

import com.ayz.gateway.api.request.ApplicationConfig;
import com.ayz.gateway.api.request.GatewayServiceSubscriber;
import com.ayz.gateway.api.request.RegistryGatewayServiceProto;
import com.ayz.gateway.api.response.GatewayCommonResult;
import com.ayz.gateway.api.server.RegistryGatewayServiceGrpc;
import com.ayz.gateway.api.server.SubscribeGatewayGroupServiceGrpc;
import com.ayz.gateway.api.utils.RequestConvertUtils;
import com.ayz.gateway.client.GrpcClient;
import com.ayz.gateway.client.GrpcClientConfig;
import com.ayz.gateway.client.constants.RequestCodeConstants;
import com.ayz.gateway.client.exception.ExecuteRequestException;
import com.ayz.gateway.client.executor.GrpcRequestExecutor;
import com.ayz.gateway.client.executor.ResponseCallback;
import com.ayz.gateway.common.constants.ApiData;
import com.ayz.gateway.common.constants.GatewayServiceData;
import com.ayz.gateway.common.result.ResponseCode;
import com.ayz.gateway.sdk.gatawayService.cache.ApiDataRepository;
import com.ayz.gateway.sdk.gatawayService.config.GatewayServiceConfig;

import com.google.common.util.concurrent.ListenableFuture;
import com.google.protobuf.Any;
import com.google.protobuf.InvalidProtocolBufferException;
import io.grpc.ManagedChannel;
import io.grpc.stub.StreamObserver;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @ClassName GatewaySericeSdk
 * @Description TODO:网关服务的SDK客户端
 * @Author 快乐的星球
 * @Date 2023/5/26 21:53
 * @Version 1.0
 **/
@Data
public class GatewayServiceSdk{

    private static final Log LOG=Log.get(GatewayServiceSdk.class);
    /**
     * 网关服务SDK的配置参数
     */
    private GatewayServiceConfig gatewayServiceConfig;
    /**
     * 网关服务与网关注册中心的通信组件
     **/
    private GrpcClient grpcClient;
    /**
     * 网关服务的基础信息类
     */
    private GatewayServiceData gatewayServiceData;
    /**
     * APIData的存储中心类
     */
    private ApiDataRepository apiDataRepository;
    /**
     * 网关全局上下文的配置项参数列表
     */
    /**
     * 定时任务线程池
     */
    private final ScheduledExecutorService scheduledExecutorService= Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setDaemon(true)
            .setNamePrefix("GatewayServiceSdkThread_").build());

    public GatewayServiceSdk(GatewayServiceConfig gatewayServiceConfig, GrpcClient grpcClient, GatewayServiceData gatewayServiceData
    ,ApiDataRepository apiDataRepository) {
        this.gatewayServiceConfig = gatewayServiceConfig;
        this.grpcClient = grpcClient;
        this.gatewayServiceData = gatewayServiceData;
        this.apiDataRepository=apiDataRepository;
    }

    public GatewayServiceSdk(GatewayServiceConfig gatewayServiceConfig, GatewayServiceData gatewayServiceData,
                             ApiDataRepository apiDataRepository) {
        this.gatewayServiceConfig = gatewayServiceConfig;
        this.gatewayServiceData = gatewayServiceData;
        GrpcClientConfig grpcClientConfig = gatewayServiceConfig.getGrpcClientConfig();

        this.grpcClient=new GrpcClient(gatewayServiceConfig.getServerAddressList(),grpcClientConfig);
        this.apiDataRepository=apiDataRepository;
    }
    /**
     * 网关服务客户端SDK组件的启动
     */
    public void start(){

        //1:完成GRPC客户端的请求执行器的注册
        this.grpcClient.registryRequestExecutors((requestExecutorRegistry -> {
            requestExecutorRegistry.registry(RequestCodeConstants.REGISTRY_GATEWAY_SERVICE_REQUEST,
                    new GrpcRequestExecutor() {
                        @Override
                        public Object request(ManagedChannel managedChannel, Object request, long timeoutMills) throws TimeoutException, ExecuteRequestException {
                            //1: 准备好请求对象
                            RegistryGatewayServiceProto.RegistryGatewayServiceRequest registryRequest=
                                    (RegistryGatewayServiceProto.RegistryGatewayServiceRequest) request;
                            //2:创建存根
                            RegistryGatewayServiceGrpc.RegistryGatewayServiceFutureStub serviceFutureStub = RegistryGatewayServiceGrpc.newFutureStub(managedChannel);
                            ListenableFuture<GatewayCommonResult.GatewayResult> future = serviceFutureStub.registryGatewayService(registryRequest);
                            try {
                                return future.get(timeoutMills, TimeUnit.MILLISECONDS);
                            } catch (InterruptedException | ExecutionException ex) {
                                throw new ExecuteRequestException("GatewayServiceSdk执行RegistryGatewayServiceRequest失败!");
                            }
                        }
                    });
            requestExecutorRegistry.registry(RequestCodeConstants.SUBSCRIBE_GATEWAY_GROUP_REQUEST,
                    new GrpcRequestExecutor() {
                        @Override
                        public void asyncRequest(ManagedChannel managedChannel, Object request, ResponseCallback responseCallback) throws TimeoutException, ExecuteRequestException {
                            //1:准备好请求对象
                            GatewayServiceSubscriber.SubscribeGatewayGroupRequest subscribeRequest=(GatewayServiceSubscriber.SubscribeGatewayGroupRequest) request;
                            //2:创建存根
                            SubscribeGatewayGroupServiceGrpc.SubscribeGatewayGroupServiceStub serviceStub = SubscribeGatewayGroupServiceGrpc.newStub(managedChannel);
                            //3:发起请求
                            io.grpc.stub.StreamObserver<com.ayz.gateway.api.response.GatewayCommonResult.GatewayResult> responseObserver=
                                    new StreamObserver<GatewayCommonResult.GatewayResult>(){
                                        @Override
                                        public void onNext(GatewayCommonResult.GatewayResult gatewayResult) {
                                            responseCallback.onSuccess(gatewayResult);
                                        }

                                        @Override
                                        public void onError(Throwable throwable) {
                                            responseCallback.onError(throwable);
                                        }

                                        @Override
                                        public void onCompleted() {
                                        }
                                    };
                            serviceStub.subscribeGatewayGroup(subscribeRequest,responseObserver);
                        }
                    });
        }));
        //2:完成GRPC客户端的启动
        this.grpcClient.start();
        //3:启动定时任务
        //3.1:启动GatewayServiceSdk默认每隔10秒种向注册中心拉取 网关服务分配到的API
        this.scheduledExecutorService.scheduleAtFixedRate(()->{
            System.out.println("-----------------------------------------------------------------");
            LOG.info("向网关注册中心注册网关服务,网关注册中心地址为:{"+grpcClient.getCurrentConnection().getServerInfo().getAddress()+"}");
            //1:准备请求对象
            RegistryGatewayServiceProto.RegistryGatewayServiceRequest request = RequestConvertUtils.generateGrpcRegistryGatewayServiceRequest(getGatewayServiceData());
            //2:发起请求
            try {
                GatewayCommonResult.GatewayResult response =(GatewayCommonResult.GatewayResult)
                        this.grpcClient.getCurrentConnection().request(RequestCodeConstants.REGISTRY_GATEWAY_SERVICE_REQUEST,
                        request, getGatewayServiceConfig().getRegistryGatewayServiceTimeoutMills());
                Any data = response.getData();
                RegistryGatewayServiceProto.RegistryGatewayServiceResponse gatewayServiceResponse = data.unpack(RegistryGatewayServiceProto.RegistryGatewayServiceResponse.class);
                //3:对响应结果进行处理
                List<ApplicationConfig.ApiData> apiDataList = gatewayServiceResponse.getApiDataList();
                List<ApiData> commonApiDataList=new ArrayList<>();
                if(!apiDataList.isEmpty()){
                    for (ApplicationConfig.ApiData apiData : apiDataList) {
                        commonApiDataList.add(RequestConvertUtils.toCommonApiData(apiData));
                    }
                }
                this.apiDataRepository.checkApiDataListChange(commonApiDataList);
            } catch (TimeoutException e) {
                LOG.error("GatewayServiceSdk向网关注册中心注册网关服务出错!",e);
            } catch (InvalidProtocolBufferException e) {
                LOG.error("解析GatewayResult的Any类型的响应数据报错!",e);
            }catch (Exception ex){
                LOG.error("出现未知错误!",ex);
            }
        },100,gatewayServiceConfig.getRegistryGatewayServiceTaskTime(),TimeUnit.MILLISECONDS);

        //3.2 启动定时任务 每隔10S一次向网关注册中心订阅一次网关业务组
        this.scheduledExecutorService.scheduleAtFixedRate(()->{
            LOG.info("向网关注册中心订阅网关业务组,网关注册中心地址为:{"+grpcClient.getCurrentConnection().getServerInfo().getAddress()+"}");
            //1:准备请求对象
            GatewayServiceSubscriber.SubscribeGatewayGroupRequest request = GatewayServiceSubscriber.SubscribeGatewayGroupRequest.newBuilder().setGatewayId(gatewayServiceData.getGatewayId()).build();
            //2:发起请求
            try {
                grpcClient.getCurrentConnection().asyncRequest(RequestCodeConstants.SUBSCRIBE_GATEWAY_GROUP_REQUEST,
                        request, new ResponseCallback() {
                            @Override
                            public void onSuccess(Object response) {
                                GatewayCommonResult.GatewayResult gatewayResult=(GatewayCommonResult.GatewayResult) response;
                                if(gatewayResult.getCode()== ResponseCode.SUBSCRIBE_GATEWAY_GROUP_FAILED){
                                    LOG.error("订阅网关业务组失败!msg:{}",gatewayResult.getMsg());
                                }else if(gatewayResult.getCode()==ResponseCode.GATEWAY_SERVICE_LOGOUT_EVENT){
                                    LOG.error("网关注册中心剔除了当前网关服务!msg:{}",gatewayResult.getMsg());
                                }else if(gatewayResult.getCode()==ResponseCode.COMMON_SUCCESS){
                                    Any data = gatewayResult.getData();
                                    try {
                                        GatewayServiceSubscriber.SubscribeGatewayGroupResponse gatewayGroupResponse = data.unpack(GatewayServiceSubscriber.SubscribeGatewayGroupResponse.class);
                                        List<ApplicationConfig.ApiData> apiDataList = gatewayGroupResponse.getApiDataList();
                                        if(!apiDataList.isEmpty()){
                                            List<ApiData> commonApiDataList=new ArrayList<>();
                                            for (ApplicationConfig.ApiData apiData : apiDataList) {
                                                commonApiDataList.add(RequestConvertUtils.toCommonApiData(apiData));
                                            }
                                            apiDataRepository.checkApiDataListChange(commonApiDataList);
                                        }
                                    } catch (InvalidProtocolBufferException e) {
                                        throw new RuntimeException("解析GatewayResult的Any类型的响应数据报错!");
                                    }
                                }
                            }
                            @Override
                            public void onError(Throwable cause) {
                                LOG.error(cause);
                            }
                        });
            } catch (TimeoutException e) {
                e.printStackTrace();
            }

        },1000L,gatewayServiceConfig.getRegistryGatewayServiceTaskTime(),TimeUnit.MILLISECONDS);

    }
    /**
     * 网关服务客户端SDK组件的关闭
     */
    public void close(){
        try {
            this.grpcClient.close();
            this.scheduledExecutorService.shutdownNow();
        } catch (Exception e) {
            LOG.error("GatewayServiceSdk关闭异常",e);
        }
    }
}
